/*
 * 
 * Created on Jul 6, 2005
 */
package com.wgo.precise.client.ui.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.forms.IManagedForm;

import com.wgo.precise.client.ui.controller.ModelStatus;
import com.wgo.precise.client.ui.controller.RequirementPlugin;
import com.wgo.precise.client.ui.model.facade.IPropertiesContainer;
import com.wgo.precise.client.ui.model.facade.IPropertyDefinitionTemplateContainer;
import com.wgo.precise.client.ui.model.facade.IRequirementTableProvider;
import com.wgo.precise.client.ui.view.action.GetPdfAction;
import com.wgo.precise.client.ui.view.editor.IModelFormPart;
import com.wgo.precise.client.ui.view.editor.properties.PropertiesFormPage;
import com.wgo.precise.client.ui.view.editor.templateselection.TemplateSelectionSectionPart;
import com.wgo.precise.client.ui.view.projecttree.CreateCategoryAction;
import com.wgo.precise.client.ui.view.projecttree.CreateRequirementAction;
import com.wgo.precise.client.ui.view.requirementstable.OpenTableEditorAction;
import com.wgo.precise.client.ui.view.util.ViewerAction;
import com.wgo.precise.common.VO.Category;
import com.wgo.precise.common.VO.Nameable;
import com.wgo.precise.common.VO.PropertySet;

/**
 * 
 * 
 * @author Petter L. H. Eide  
 */
public class CategoryWrapper extends NodeParent<NodeParent, NodeChild, Category> implements IRequirementTableProvider<NodeParent,NodeChild>, IPropertyDefinitionTemplateContainer{

	private static final Class<Category> PARENT_INTERFACE = Category.class;
	private static final String PARENT_CORE_METHOD_NAME = "Project";
	private static final String GET_CHILDREN_METHODS_NAME[] = {"getSubCategories", "getRequirements"};

	private List<AbstractPropertySpesification> requirementPropertySpesifications;

    private Category category;
    
    private Map<PropertySet, PropertySetWrapper> definitionSets;

    protected CategoryWrapper(Category category) {
        super(category, PARENT_INTERFACE, PARENT_CORE_METHOD_NAME, GET_CHILDREN_METHODS_NAME);
        init(category);
    }

    protected CategoryWrapper(Category nameable, CategoryWrapper parent) {
		super(nameable, parent, PARENT_INTERFACE, PARENT_CORE_METHOD_NAME, GET_CHILDREN_METHODS_NAME);
	}
    
    protected CategoryWrapper(Category nameable, ProjectWrapper parent) {
		super(nameable, parent, PARENT_INTERFACE, PARENT_CORE_METHOD_NAME, GET_CHILDREN_METHODS_NAME);
	}

	/**
	 * @see com.wgo.precise.client.ui.model.NodeChild#init(remato.common.domain.helpers.Nameable)
	 */
	@Override
	protected void init(Nameable nameable) {
        setDisplayImageKey(ISharedImages.IMG_OBJ_FOLDER);
        category = (Category)nameable;
        definitionSets = new Hashtable<PropertySet, PropertySetWrapper>();
        requirementPropertySpesifications = Collections.synchronizedList(new LinkedList<AbstractPropertySpesification>());
	}

	/**
     * @see com.wgo.precise.client.ui.model.facade.IMenuItemsProvider#getMenuItemActions()
     */
    @Override
    public List<ViewerAction> getMenuItemActions() {
        List<ViewerAction> actionList= new ArrayList<ViewerAction>();
        actionList.add(new CreateCategoryAction(this));
        actionList.add(new CreateRequirementAction(this));
//        actionList.add(new CreatePdfAction(RequirementPlugin.getInstance().getActiveShell().getShell(),category));
        actionList.add(new GetPdfAction(RequirementPlugin.getInstance().getActiveShell().getShell(), this));
        if (hasChildren()) { 
        	actionList.add(new OpenTableEditorAction(this));
        }
        actionList.addAll(super.getMenuItemActions());
        return actionList;
    }

    /**
     * Ovverided to make public.
     * 
     * @see com.wgo.precise.client.ui.model.NodeChild#getUserDefinedTypes()
     */
    @Override
    public List<AbstractPropertySpesification> getUserDefinedTypes() {
        return super.getUserDefinedTypes();
    }

    public int getSortingOrder() {
        return Configuration.CATEGORY_SORT_ORDER;
    }

    public Collection<PropertySetWrapper> getPropertyDefinitionSets() {
		Map<PropertySet, PropertySetWrapper> newDefinitionSets = new Hashtable<PropertySet, PropertySetWrapper>();
		synchronized (definitionSets) {
	    	for (PropertySet set : category.getPropertySets()) {
	    		PropertySetWrapper wrapper = definitionSets.remove(set);
	        	if (null != wrapper) {
	        		newDefinitionSets.put(set, wrapper);
	        	} else {
	        		newDefinitionSets.put(set, RequirementPlugin.getInstance().getSession().getWrapperFactory().<PropertySetWrapper>getWrapper(set));
	        	}
	        }
	        for (PropertySetWrapper wrapper : definitionSets.values()) {
	        	RequirementPlugin.log(new ModelStatus(IStatus.WARNING, getClass().getSimpleName() + "Inconsistent property templates collection: " + wrapper + " not removed."));
	        }
	        definitionSets = newDefinitionSets;
		}
		return definitionSets.values();	
    }
    
//    protected Collection<PropertyDefinitionSetWrapper> getAllPropertyDefinitionSetsForRequirements() {
//    	Collection<PropertyDefinitionSetWrapper> list = new ArrayList<PropertyDefinitionSetWrapper>();
//    	list.addAll(getPropertyDefinitionSets());
//    	if (getParent() instanceof CategoryWrapper) {
//        	list.addAll(((CategoryWrapper)getParent()).getPropertyDefinitionSets());
//    	}
//    	return list;
//    }
    
    public synchronized void addPropertyDefinitionSetWrapper(PropertySetWrapper definitionSet) {
    	PropertySet set = definitionSet.getDomainModelObject();
    	category.addPropertySet(set);
    	definitionSets.put(set, definitionSet);
    	RequirementPlugin.getInstance().getPreciseSubject().notifyModelChanged(this);
    }
    public synchronized void removePropertyDefinitionSetWrapper(PropertySetWrapper definitionSet) {
    	PropertySet set = definitionSet.getDomainModelObject();
    	category.removePropertySet(set);
    	definitionSets.remove(set);
    	RequirementPlugin.getInstance().getPreciseSubject().notifyModelChanged(this);
    }
    
	/**
	 * @see com.wgo.precise.client.ui.model.facade.DNDTarget#validTransfer(com.wgo.precise.client.ui.model.ClientModelItem)
	 */
    @Override
	public boolean validTransfer(IPropertiesContainer type) {
		boolean valid = false;
		if (type instanceof RequirementWrapper || type instanceof CategoryWrapper) {
			valid = true;
		}
		return valid && super.validTransfer(type);
	}

	public List<AbstractPropertySpesification> getRequirementPropertySpesifications() {
        return requirementPropertySpesifications;
	}

	public void addRequirementPropertySpesification(AbstractPropertySpesification element) {
        requirementPropertySpesifications.add(element);
        markDirty();
	}

	public void removeRequirementPropertySpesification(AbstractPropertySpesification element) {
        requirementPropertySpesifications.remove(element);
        markDirty();
	}

	public synchronized void updateRequirementPropertySpesification(AbstractPropertySpesification element) {
        int position = requirementPropertySpesifications.indexOf(element);
        requirementPropertySpesifications.remove(element);
        requirementPropertySpesifications.add(position, element);
        markDirty();
	}

	public synchronized boolean insertAfter(AbstractPropertySpesification insert, AbstractPropertySpesification after) {
        if (insert.equals(after)) {
            return false;
        }
        requirementPropertySpesifications.remove(insert);
        int newIndex = requirementPropertySpesifications.indexOf(after) + 1;
        requirementPropertySpesifications.add(newIndex, insert);
        int position = requirementPropertySpesifications.get(newIndex -1 ).getPosition() + 1;
        for (AbstractPropertySpesification spec : requirementPropertySpesifications.subList(newIndex, requirementPropertySpesifications.size())) {
            spec.setPosition(position);
            position++;
        }
        markDirty();
        return true;
	}
    public AbstractPropertySpesification getRequirementPropertySpesification(int position) {
        return requirementPropertySpesifications.get(position);
    }

	@Override
	public List<IModelFormPart> getPropertiesFormParts(PropertiesFormPage page, IManagedForm managedForm) {
		List<IModelFormPart> formParts = super.getPropertiesFormParts(page, managedForm); 
    	Composite body = managedForm.getForm().getBody();
    	Composite section = managedForm.getToolkit().createComposite(body);
    	section.setLayout(new FillLayout());
    	formParts.add(new TemplateSelectionSectionPart(page, section));
		return formParts;
	}

}
